package org.sxp.modules.dataworks.controller;

import java.util.Arrays;
import java.util.List;

import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.xxl.job.admin.controller.JobInfoController;
import com.xxl.job.admin.core.model.XxlJobInfo;
import com.xxl.job.admin.core.model.XxlJobLog;
import com.xxl.job.admin.dao.XxlJobInfoDao;
import com.xxl.job.admin.dao.XxlJobLogDao;
import com.xxl.job.admin.service.XxlJobService;
import com.xxl.job.core.biz.model.ReturnT;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.validation.annotation.Validated;
import org.sxp.common.exception.BusinessException;
import org.sxp.modules.dataworks.dto.DevelopDTO;
import org.sxp.modules.dataworks.dto.FlowScriptDTO;
import org.sxp.modules.dataworks.entity.DevelopDO;
import org.sxp.modules.dataworks.entity.FlowDO;
import org.sxp.modules.dataworks.service.FlowService;
import org.sxp.modules.dataworks.dto.FlowDTO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.springframework.web.bind.annotation.*;
import org.sxp.common.annotation.SysLog;
import org.sxp.common.utils.PageInfo;
import org.sxp.common.utils.PageResult;
import org.sxp.common.utils.Query;
import org.sxp.common.web.WrapperResponse;
import org.sxp.modules.dataworks.utils.XxlJobLogCaptureUtil;
import org.sxp.modules.sys.controller.AbstractController;
import org.apache.shiro.authz.annotation.RequiresPermissions;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;

/**
 * 作业流程表
 * @author 沈兴平
 * @date 2022/02/19
 */
@Controller
@RequestMapping(value = "/dataworks/flow")
@Api(description="Flow", tags = "作业流程表")
@SysLog(modules = "dataworks", value = "作业流程表")
public class FlowController extends AbstractController{
    @Autowired
    private FlowService flowService;

    @Resource
    public XxlJobLogDao xxlJobLogDao;
    @Resource
    private XxlJobInfoDao xxlJobInfoDao;
    @Resource
    private JobInfoController jobInfoController;
    @Resource
    private XxlJobService xxlJobService;

    @RequestMapping("/index")
    public String module(HttpServletRequest request, Model model){
        jobInfoController.index(request, model, -1);
        return "modules/dataworks/flow.html";
    }

    /**
     * 列表
     */
    @ApiImplicitParams({
            @ApiImplicitParam(name="pageNum", value = "当前页码", dataType="int", paramType = "header"),
            @ApiImplicitParam(name="pageSize",value="每页条目",dataType="int", paramType = "header"),
            @ApiImplicitParam(name="orderField",value="排序字段",dataType="string", paramType = "header"),
            @ApiImplicitParam(name="orderType",value="排序类型",dataType="string", paramType = "header", example = "asc或者desc")
    })
    @RequestMapping(value = "/list",method = {RequestMethod.POST})
    @ApiOperation(value = "查询列表")
    @RequiresPermissions("dataworks:flow:list")
    @ResponseBody
    public WrapperResponse<List<FlowDTO>> list(FlowDTO params) throws Exception{
        //请求头获取分页参数
        PageInfo pageInfo = buildPageInfo();
        IPage<FlowDO> page = flowService.page(
                new Query<FlowDO>().getPage(pageInfo)
                ,new LambdaQueryWrapper<FlowDO>()
                        .eq(FlowDO::getSpaceId, params.getSpaceId())
                        .like(StrUtil.isNotBlank(params.getName()), FlowDO::getName, params.getName())
        );

        for(FlowDO flowDO : page.getRecords()){
            if(flowDO.getJobinfoId() != null){
                XxlJobInfo jobInfo = xxlJobInfoDao.loadById(flowDO.getJobinfoId());
                if(jobInfo != null){
                    flowDO.setJobinfoName(jobInfo.getName());
                }
            }
        }
        return (WrapperResponse)WrapperResponse.success(new PageResult(page));
    }


    /**
     * 信息
     */
    @RequestMapping(value = "/info/{id}", method = {RequestMethod.GET})
    @ApiOperation(value = "查询")
    @RequiresPermissions("dataworks:flow:info")
    @ResponseBody
    public WrapperResponse<FlowDTO> info(@PathVariable String id) throws Exception{
        FlowDO flow = flowService.getById(id);
        if(flow != null && flow.getJobinfoId() != null){
            XxlJobInfo jobInfo = xxlJobInfoDao.loadById(flow.getJobinfoId());
            if(jobInfo != null){
                flow.setJobinfoName(jobInfo.getName());
            }
        }
        return (WrapperResponse)WrapperResponse.success(flow);
    }

    /**
     * 保存作业流程
     */
    @RequestMapping(value = "/saveFlowScript",method = {RequestMethod.POST})
    @ApiOperation(value = "保存作业流程")
    @SysLog("保存作业流程")
    @RequiresPermissions("dataworks:flow:save")
    @ResponseBody
    public WrapperResponse<FlowDTO> saveFlowScript(@RequestBody List<FlowScriptDTO> flow, @RequestParam("id") String id) throws Exception{
        FlowDO flowDO = flowService.getById(id);
        flowDO.setFlowScript(JSON.toJSONString(flow));
        flowService.updateById(flowDO);
        return (WrapperResponse)WrapperResponse.success(null);
    }

    /**
     * 执行调度
     */
    @RequestMapping(value = "/executeJob", method = {RequestMethod.POST})
    @ApiOperation(value = "执行调度")
    @ResponseBody
    public WrapperResponse excuteJob(@RequestBody FlowDTO flowDTO) throws Exception{
        List<XxlJobLog> activeLog = xxlJobLogDao.findJobActiveLog(flowDTO.getJobinfoId());
        if(activeLog != null && activeLog.size() > 0){
            return WrapperResponse.fail("工作绑定的调度正在执行任务，请结束后再执行!!!", null);
        }
        // 执行前先保存
        WrapperResponse response = update(flowDTO);

        if(response.getCode() == WrapperResponse.SUCCESS){
            ReturnT<XxlJobInfo> returnT = jobInfoController.loadById(flowDTO.getJobinfoId());
            if(returnT.getCode() == ReturnT.SUCCESS_CODE && returnT.getContent() != null){
                XxlJobInfo jobInfo = returnT.getContent();
                try {
                    String snapshotId = IdUtil.simpleUUID();
                    XxlJobLogCaptureUtil.jobLogContext.set(snapshotId);
                    ReturnT<String> triggerReturnT = jobInfoController.triggerJob(flowDTO.getJobinfoId(), jobInfo.getExecutorParam(), null);
                    if (triggerReturnT.getCode() == ReturnT.SUCCESS_CODE) {
                        int index = 5;
                        while(index > 0){
                            XxlJobLog jobLog = xxlJobLogDao.loadBySnapshotId(snapshotId);
                            if(jobLog != null){
                                return WrapperResponse.success(jobLog.getId());
                            }
                            Thread.sleep(1000);
                            index--;
                        }
                    } else {
                        throw new BusinessException("调度执行失败:" + triggerReturnT.getMsg());
                    }
                }catch (Exception e){
                    throw e;
                }finally {
                    XxlJobLogCaptureUtil.jobLogContext.remove();
                }
            }else{
                return WrapperResponse.fail("调度任务不存在，可能被移除，请重新配置。", null);
            }
        }else{
            return WrapperResponse.fail("执行前保存失败!!!");
        }
        return WrapperResponse.success(null);
    }

    /**
     * 绑定调度
     */
    @RequestMapping(value = "/bindJob", method = {RequestMethod.POST})
    @ApiOperation(value = "绑定调度")
    @ResponseBody
    public WrapperResponse bindJob(@RequestBody XxlJobInfo jobInfo, @RequestParam String id) throws Exception{
        FlowDO entity = flowService.getById(id);
        ReturnT<String> r = null;
        if(jobInfo.getId() > 0){
            ReturnT<XxlJobInfo> oldJobInfo = jobInfoController.loadById(jobInfo.getId());
            r = jobInfoController.update(jobInfo);
            r.setContent(String.valueOf(jobInfo.getId()));
            if(r.getCode() == ReturnT.SUCCESS_CODE && oldJobInfo.getContent().getTriggerStatus() != jobInfo.getTriggerStatus()){
               // 绑定调度的运行状态不等于老数据
               if(jobInfo.getTriggerStatus() == 1){
                   jobInfoController.start(jobInfo.getId());
               }else{
                   jobInfoController.pause(jobInfo.getId());
               }
            }
        }else{
            r = jobInfoController.add(jobInfo);
            if(r.getCode() == ReturnT.SUCCESS_CODE){
                entity.setJobinfoId(Integer.parseInt(r.getContent()));
                flowService.updateById(entity);

                // 绑定调度的运行状态不等于老数据
                if(jobInfo.getTriggerStatus() == 1){
                    jobInfoController.start(jobInfo.getId());
                }
            }
        }
        return r.getCode() == ReturnT.SUCCESS_CODE ? WrapperResponse.success(r.getContent()) : WrapperResponse.fail(r.getMsg(), r.getContent());
    }

    /**
     * 保存
     */
    @RequestMapping(value = "/save",method = {RequestMethod.POST})
    @ApiOperation(value = "保存")
    @SysLog("保存")
    @RequiresPermissions("dataworks:flow:save")
    @ResponseBody
    public WrapperResponse<FlowDTO> save(@RequestBody FlowDTO flow) throws Exception{
        flowService.save(FlowDO.copyBean(flow));

        return (WrapperResponse)WrapperResponse.success(null);
    }

    /**
     * 修改
     */
    @RequestMapping(value = "/update",method = {RequestMethod.POST})
    @ApiOperation(value = "修改")
    @SysLog("修改")
    @RequiresPermissions("dataworks:flow:update")
    @ResponseBody
    public WrapperResponse<FlowDTO> update(@RequestBody FlowDTO flow) throws Exception{
        flowService.updateById(FlowDO.copyBean(flow));
        
        return (WrapperResponse)WrapperResponse.success(null);
    }

    /**
     * 批量删除
     */
    @RequestMapping(value = "/deleteBatch",method = {RequestMethod.POST})
    @ApiOperation(value = "批量删除")
    @SysLog("批量删除")
    @RequiresPermissions("dataworks:flow:deleteBatch")
    @ResponseBody
    public WrapperResponse deleteBatch(@RequestBody String[] ids) throws Exception{
        for(String id : ids){
            FlowDO flowDO = flowService.getById(id);
            boolean boo = flowService.removeById(id);
            if(boo && flowDO.getJobinfoId() != null){
                xxlJobService.remove(flowDO.getJobinfoId());
            }
        }
        return WrapperResponse.success(null);
    }
}
